package org.xbill.DNS;

import java.io.IOException;
import java.io.PrintStream;
import java.io.Serializable;
import java.text.DecimalFormat;

public class Name
  implements Comparable, Serializable
{
  private static final int LABEL_COMPRESSION = 192;
  private static final int LABEL_MASK = 192;
  private static final int LABEL_NORMAL = 0;
  private static final int MAXLABEL = 63;
  private static final int MAXLABELS = 128;
  private static final int MAXNAME = 255;
  private static final int MAXOFFSETS = 7;
  private static final DecimalFormat byteFormat;
  public static final Name empty;
  private static final byte[] emptyLabel = new byte[1];
  private static final byte[] lowercase;
  public static final Name root;
  private static final long serialVersionUID = 578243060L;
  private static final Name wild;
  private static final byte[] wildLabel;
  private int hashcode;
  private byte[] name;
  private long offsets;

  static
  {
    byte[] arrayOfByte = new byte[2];
    arrayOfByte[0] = 1;
    arrayOfByte[1] = 42;
    wildLabel = arrayOfByte;
    byteFormat = new DecimalFormat();
    lowercase = new byte[256];
    byteFormat.setMinimumIntegerDigits(3);
    int i = 0;
    if (i >= lowercase.length)
    {
      root = new Name();
      root.appendSafe(emptyLabel, 0, 1);
      empty = new Name();
      empty.name = new byte[0];
      wild = new Name();
      wild.appendSafe(wildLabel, 0, 1);
      return;
    }
    if ((i < 65) || (i > 90))
      lowercase[i] = (byte)i;
    while (true)
    {
      while (true)
        ++i;
      lowercase[i] = (byte)(97 + i - 65);
    }
  }

  public Name(String paramString)
    throws TextParseException
  {
    this(paramString, null);
  }

  public Name(String paramString, Name paramName)
    throws TextParseException
  {
    if (paramString.equals(""))
      throw parseException(paramString, "empty name");
    if (paramString.equals("@"))
      if (paramName == null)
        copy(empty, this);
    while (true)
    {
      while (true)
      {
        return;
        copy(paramName, this);
      }
      if (!(paramString.equals(".")))
        break;
      copy(root, this);
    }
    int i = -1;
    int j = 1;
    byte[] arrayOfByte = new byte[64];
    int k = 0;
    int l = 0;
    int i1 = 0;
    int i2 = 0;
    int i3 = 0;
    if (i3 >= paramString.length())
    {
      if ((l <= 0) || (l >= 3))
        break label370;
      throw parseException(paramString, "bad escape");
    }
    int i4 = (byte)paramString.charAt(i3);
    if (k != 0)
      if ((i4 >= 48) && (i4 <= 57) && (l < 3))
      {
        ++l;
        i1 = i1 * 10 + i4 - 48;
        if (i1 > 255)
          throw parseException(paramString, "bad escape");
        if (l < 3);
      }
    while (true)
    {
      while (true)
      {
        while (true)
        {
          while (true)
          {
            while (true)
              ++i3;
            i4 = i1;
            do
            {
              if (j <= 63)
                break label235;
              throw parseException(paramString, "label too long");
            }
            while ((l <= 0) || (l >= 3));
            throw parseException(paramString, "bad escape");
            label235: i = j;
            int i6 = j + 1;
            arrayOfByte[j] = i4;
            k = 0;
            j = i6;
          }
          if (i4 != 92)
            break;
          k = 1;
          l = 0;
          i1 = 0;
        }
        if (i4 != 46)
          break;
        if (i == -1)
          throw parseException(paramString, "invalid empty label");
        arrayOfByte[0] = (byte)(j - 1);
        appendFromString(paramString, arrayOfByte, 0, 1);
        i = -1;
        j = 1;
      }
      if (i == -1)
        i = i3;
      if (j > 63)
        throw parseException(paramString, "label too long");
      int i5 = j + 1;
      arrayOfByte[j] = i4;
      j = i5;
    }
    if (k != 0)
      label370: throw parseException(paramString, "bad escape");
    if (i == -1)
    {
      appendFromString(paramString, emptyLabel, 0, 1);
      i2 = 1;
    }
    while (true)
    {
      while (true)
      {
        if ((paramName == null) || (i2 != 0));
        appendFromString(paramString, paramName.name, 0, paramName.getlabels());
      }
      arrayOfByte[0] = (byte)(j - 1);
      appendFromString(paramString, arrayOfByte, 0, 1);
    }
  }

  public Name(DNSInput paramDNSInput)
    throws WireParseException
  {
    int i = 0;
    byte[] arrayOfByte = new byte[64];
    int j = 0;
    while (true)
    {
      int l;
      do
      {
        int k;
        while (true)
        {
          while (true)
          {
            if (i != 0)
            {
              if (j != 0)
                paramDNSInput.restore();
              return;
            }
            k = paramDNSInput.readU8();
            switch (k & 0xC0)
            {
            default:
              throw new WireParseException("bad label type");
            case 0:
              if (getlabels() >= 128)
                throw new WireParseException("too many labels");
              if (k != 0)
                break;
              append(emptyLabel, 0, 1);
              i = 1;
            case 192:
            }
          }
          arrayOfByte[0] = (byte)k;
          paramDNSInput.readByteArray(arrayOfByte, 1, k);
          append(arrayOfByte, 0, 1);
        }
        l = paramDNSInput.readU8() + ((k & 0xFFFFFF3F) << 8);
        if (Options.check("verbosecompression"))
          System.err.println("currently " + paramDNSInput.current() + ", pointer to " + l);
        if (l >= paramDNSInput.current() - 2)
          throw new WireParseException("bad compression");
        if (j == 0)
        {
          paramDNSInput.save();
          j = 1;
        }
        paramDNSInput.jump(l);
      }
      while (!(Options.check("verbosecompression")));
      System.err.println("current name '" + this + "', seeking to " + l);
    }
  }

  public Name(Name paramName, int paramInt)
  {
    int i = paramName.labels();
    if (paramInt > i)
      throw new IllegalArgumentException("attempted to remove too many labels");
    this.name = paramName.name;
    setlabels(i - paramInt);
    int j = 0;
    while (true)
    {
      if ((j >= 7) || (j >= i - paramInt))
        return;
      setoffset(j, paramName.offset(j + paramInt));
      ++j;
    }
  }

  public Name(byte[] paramArrayOfByte)
    throws IOException
  {
    this(new DNSInput(paramArrayOfByte));
  }

  private final void append(byte[] paramArrayOfByte, int paramInt1, int paramInt2)
    throws NameTooLongException
  {
    int i;
    int j;
    int k;
    int l;
    int i3;
    if (this.name == null)
    {
      i = 0;
      j = 0;
      k = 0;
      l = paramInt1;
    }
    while (true)
    {
      while (k >= paramInt2)
      {
        i3 = i + j;
        if (i3 <= 255)
          break label113;
        throw new NameTooLongException();
        i = this.name.length - offset(0);
      }
      int i1 = paramArrayOfByte[l];
      if (i1 > 63)
        throw new IllegalStateException("invalid label");
      int i2 = i1 + 1;
      l += i2;
      j += i2;
      ++k;
    }
    label113: int i4 = getlabels();
    int i5 = i4 + paramInt2;
    if (i5 > 128)
      throw new IllegalStateException("too many labels");
    byte[] arrayOfByte = new byte[i3];
    if (i != 0)
      System.arraycopy(this.name, offset(0), arrayOfByte, 0, i);
    System.arraycopy(paramArrayOfByte, paramInt1, arrayOfByte, i, j);
    this.name = arrayOfByte;
    int i6 = 0;
    int i7 = i;
    while (true)
    {
      if (i6 >= paramInt2)
      {
        setlabels(i5);
        return;
      }
      setoffset(i4 + i6, i7);
      i7 += 1 + arrayOfByte[i7];
      ++i6;
    }
  }

  private final void appendFromString(String paramString, byte[] paramArrayOfByte, int paramInt1, int paramInt2)
    throws TextParseException
  {
    try
    {
      append(paramArrayOfByte, paramInt1, paramInt2);
      return;
    }
    catch (NameTooLongException localNameTooLongException)
    {
      throw parseException(paramString, "Name too long");
    }
  }

  private final void appendSafe(byte[] paramArrayOfByte, int paramInt1, int paramInt2)
  {
    try
    {
      append(paramArrayOfByte, paramInt1, paramInt2);
      return;
    }
    catch (NameTooLongException localNameTooLongException)
    {
    }
  }

  private String byteString(byte[] paramArrayOfByte, int paramInt)
  {
    StringBuffer localStringBuffer = new StringBuffer();
    int i = paramInt + 1;
    int j = paramArrayOfByte[paramInt];
    int k = i;
    if (k >= i + j)
      return localStringBuffer.toString();
    int l = 0xFF & paramArrayOfByte[k];
    if ((l <= 32) || (l >= 127))
    {
      localStringBuffer.append('\\');
      localStringBuffer.append(byteFormat.format(l));
    }
    while (true)
    {
      while (true)
      {
        while (true)
          ++k;
        if ((l != 34) && (l != 40) && (l != 41) && (l != 46) && (l != 59) && (l != 92) && (l != 64) && (l != 36))
          break;
        localStringBuffer.append('\\');
        localStringBuffer.append((char)l);
      }
      localStringBuffer.append((char)l);
    }
  }

  public static Name concatenate(Name paramName1, Name paramName2)
    throws NameTooLongException
  {
    Object localObject;
    if (paramName1.isAbsolute())
      localObject = paramName1;
    while (true)
    {
      return localObject;
      Name localName = new Name();
      copy(paramName1, localName);
      localName.append(paramName2.name, paramName2.offset(0), paramName2.getlabels());
      localObject = localName;
    }
  }

  private static final void copy(Name paramName1, Name paramName2)
  {
    if (paramName1.offset(0) == 0)
    {
      paramName2.name = paramName1.name;
      paramName2.offsets = paramName1.offsets;
      return;
    }
    int i = paramName1.offset(0);
    int j = paramName1.name.length - i;
    int k = paramName1.labels();
    paramName2.name = new byte[j];
    System.arraycopy(paramName1.name, i, paramName2.name, 0, j);
    int l = 0;
    while (true)
    {
      while ((l >= k) || (l >= 7))
        paramName2.setlabels(k);
      paramName2.setoffset(l, paramName1.offset(l) - i);
      ++l;
    }
  }

  private final boolean equals(byte[] paramArrayOfByte, int paramInt)
  {
    int i8;
    int i = labels();
    int j = 0;
    int k = offset(0);
    if (j >= i)
      i8 = 1;
    while (true)
    {
      return i8;
      if (this.name[k] == paramArrayOfByte[paramInt])
        break;
      i8 = 0;
    }
    byte[] arrayOfByte1 = this.name;
    int l = k + 1;
    int i1 = arrayOfByte1[k];
    int i2 = paramInt + 1;
    if (i1 > 63)
      throw new IllegalStateException("invalid label");
    int i3 = 0;
    k = l;
    int i4 = i2;
    while (true)
    {
      int i5;
      int i7;
      while (true)
      {
        while (i3 >= i1)
        {
          ++j;
          paramInt = i4;
        }
        byte[] arrayOfByte2 = lowercase;
        byte[] arrayOfByte3 = this.name;
        i5 = k + 1;
        int i6 = arrayOfByte2[(0xFF & arrayOfByte3[k])];
        byte[] arrayOfByte4 = lowercase;
        i7 = i4 + 1;
        if (i6 == arrayOfByte4[(0xFF & paramArrayOfByte[i4])])
          break;
        i8 = 0;
      }
      i3 += 1;
      k = i5;
      i4 = i7;
    }
  }

  public static Name fromConstantString(String paramString)
  {
    Name localName;
    try
    {
      localName = fromString(paramString, null);
      return localName;
    }
    catch (TextParseException localTextParseException)
    {
      throw new IllegalArgumentException("Invalid name '" + paramString + "'");
    }
  }

  public static Name fromString(String paramString)
    throws TextParseException
  {
    return fromString(paramString, null);
  }

  public static Name fromString(String paramString, Name paramName)
    throws TextParseException
  {
    Name localName;
    if ((paramString.equals("@")) && (paramName != null))
      localName = paramName;
    while (true)
    {
      while (true)
      {
        return localName;
        if (!(paramString.equals(".")))
          break;
        localName = root;
      }
      localName = new Name(paramString, paramName);
    }
  }

  private final int getlabels()
  {
    return (int)(0xFF & this.offsets);
  }

  private final int offset(int paramInt)
  {
    int k;
    if ((paramInt == 0) && (getlabels() == 0))
      k = 0;
    while (true)
    {
      return k;
      if ((paramInt < 0) || (paramInt >= getlabels()))
        throw new IllegalArgumentException("label out of range");
      if (paramInt >= 7)
        break;
      int l = 8 * (7 - paramInt);
      k = 0xFF & (int)(this.offsets >>> l);
    }
    int i = offset(6);
    int j = 6;
    while (true)
    {
      while (j >= paramInt)
        k = i;
      i += 1 + this.name[i];
      ++j;
    }
  }

  private static TextParseException parseException(String paramString1, String paramString2)
  {
    return new TextParseException("'" + paramString1 + "': " + paramString2);
  }

  private final void setlabels(int paramInt)
  {
    this.offsets = (0xFFFFFF00 & this.offsets);
    this.offsets |= paramInt;
  }

  private final void setoffset(int paramInt1, int paramInt2)
  {
    if (paramInt1 >= 7);
    while (true)
    {
      return;
      int i = 8 * (7 - paramInt1);
      this.offsets &= (0xFFFFFFFF ^ 255L << i);
      this.offsets |= paramInt2 << i;
    }
  }

  public int compareTo(Object paramObject)
  {
    int k;
    int l;
    int i6;
    Name localName = (Name)paramObject;
    if (this == localName)
    {
      i6 = 0;
      return i6;
    }
    int i = labels();
    int j = localName.labels();
    if (i > j)
    {
      k = j;
      l = 1;
    }
    while (true)
    {
      while (true)
      {
        while (true)
        {
          if (l <= k)
            break label62;
          i6 = i - j;
        }
        k = i;
      }
      label62: int i1 = offset(i - l);
      int i2 = localName.offset(j - l);
      int i3 = this.name[i1];
      int i4 = localName.name[i2];
      int i5 = 0;
      while (true)
      {
        while (true)
        {
          while ((i5 >= i3) || (i5 >= i4))
          {
            if (i3 == i4)
              break label196;
            i6 = i3 - i4;
          }
          int i7 = lowercase[(0xFF & this.name[(1 + i5 + i1)])] - lowercase[(0xFF & localName.name[(1 + i5 + i2)])];
          if (i7 == 0)
            break;
          i6 = i7;
        }
        ++i5;
      }
      label196: ++l;
    }
  }

  public boolean equals(Object paramObject)
  {
    boolean bool;
    if (paramObject == this)
      bool = true;
    while (true)
    {
      Name localName;
      while (true)
      {
        while (true)
        {
          while (true)
          {
            return bool;
            if ((paramObject != null) && (paramObject instanceof Name))
              break;
            bool = false;
          }
          localName = (Name)paramObject;
          if (localName.hashcode == 0)
            localName.hashCode();
          if (this.hashcode == 0)
            hashCode();
          if (localName.hashcode == this.hashcode)
            break;
          bool = false;
        }
        if (localName.labels() == labels())
          break;
        bool = false;
      }
      bool = equals(localName.name, localName.offset(0));
    }
  }

  public Name fromDNAME(DNAMERecord paramDNAMERecord)
    throws NameTooLongException
  {
    Object localObject;
    Name localName1 = paramDNAMERecord.getName();
    Name localName2 = paramDNAMERecord.getTarget();
    if (!(subdomain(localName1)))
    {
      localObject = null;
      return localObject;
    }
    int i = labels() - localName1.labels();
    int j = length() - localName1.length();
    int k = offset(0);
    int l = localName2.labels();
    int i1 = localName2.length();
    if (j + i1 > 255)
      throw new NameTooLongException();
    Name localName3 = new Name();
    localName3.setlabels(i + l);
    localName3.name = new byte[j + i1];
    System.arraycopy(this.name, k, localName3.name, 0, j);
    System.arraycopy(localName2.name, 0, localName3.name, j, i1);
    int i2 = 0;
    int i3 = 0;
    while (true)
    {
      while ((i2 >= 7) || (i2 >= i + l))
        localObject = localName3;
      localName3.setoffset(i2, i3);
      i3 += 1 + localName3.name[i3];
      ++i2;
    }
  }

  public byte[] getLabel(int paramInt)
  {
    int i = offset(paramInt);
    int j = (byte)(1 + this.name[i]);
    byte[] arrayOfByte = new byte[j];
    System.arraycopy(this.name, i, arrayOfByte, 0, j);
    return arrayOfByte;
  }

  public String getLabelString(int paramInt)
  {
    int i = offset(paramInt);
    return byteString(this.name, i);
  }

  public int hashCode()
  {
    int k;
    if (this.hashcode != 0)
    {
      k = this.hashcode;
      return k;
    }
    int i = 0;
    int j = offset(0);
    while (true)
    {
      while (j >= this.name.length)
      {
        this.hashcode = i;
        k = this.hashcode;
      }
      i += (i << 3) + lowercase[(0xFF & this.name[j])];
      ++j;
    }
  }

  public boolean isAbsolute()
  {
    int i;
    if (labels() == 0)
      i = 0;
    while (true)
    {
      while (true)
      {
        return i;
        if (this.name[(this.name.length - 1)] != 0)
          break;
        i = 1;
      }
      i = 0;
    }
  }

  public boolean isWild()
  {
    int i;
    if (labels() == 0)
      i = 0;
    while (true)
    {
      while (true)
      {
        return i;
        if ((this.name[0] != 1) || (this.name[1] != 42))
          break;
        i = 1;
      }
      i = 0;
    }
  }

  public int labels()
  {
    return getlabels();
  }

  public short length()
  {
    int i;
    if (getlabels() == 0)
      i = 0;
    while (true)
    {
      return i;
      i = (short)(this.name.length - offset(0));
    }
  }

  public Name relativize(Name paramName)
  {
    Object localObject;
    if ((paramName == null) || (!(subdomain(paramName))))
      localObject = this;
    while (true)
    {
      return localObject;
      Name localName = new Name();
      copy(this, localName);
      int i = length() - paramName.length();
      localName.setlabels(localName.labels() - paramName.labels());
      localName.name = new byte[i];
      System.arraycopy(this.name, offset(0), localName.name, 0, i);
      localObject = localName;
    }
  }

  public boolean subdomain(Name paramName)
  {
    boolean bool;
    int i = labels();
    int j = paramName.labels();
    if (j > i)
      bool = false;
    while (true)
    {
      while (true)
      {
        return bool;
        if (j != i)
          break;
        bool = equals(paramName);
      }
      bool = paramName.equals(this.name, offset(i - j));
    }
  }

  public String toString()
  {
    String str;
    int i = labels();
    if (i == 0)
      str = "@";
    while (true)
    {
      return str;
      if ((i != 1) || (this.name[offset(0)] != 0))
        break;
      str = ".";
    }
    StringBuffer localStringBuffer = new StringBuffer();
    int j = 0;
    int k = offset(0);
    while (true)
    {
      int l;
      if (j >= i);
      do
      {
        while (true)
        {
          if (!(isAbsolute()))
            localStringBuffer.deleteCharAt(localStringBuffer.length() - 1);
          str = localStringBuffer.toString();
        }
        l = this.name[k];
        if (l > 63)
          throw new IllegalStateException("invalid label");
      }
      while (l == 0);
      localStringBuffer.append(byteString(this.name, k));
      localStringBuffer.append('.');
      k += l + 1;
      ++j;
    }
  }

  public void toWire(DNSOutput paramDNSOutput, Compression paramCompression)
  {
    if (!(isAbsolute()))
      throw new IllegalArgumentException("toWire() called on non-absolute name");
    int i = labels();
    int j = 0;
    while (true)
    {
      Name localName;
      if (j >= i - 1)
      {
        paramDNSOutput.writeU8(0);
        return;
      }
      if (j == 0)
        localName = this;
      while (true)
      {
        while (true)
        {
          int k = -1;
          if (paramCompression != null)
            k = paramCompression.get(localName);
          if (k < 0)
            break label97;
          paramDNSOutput.writeU16(k | 0xC000);
        }
        localName = new Name(this, j);
      }
      if (paramCompression != null)
        label97: paramCompression.add(paramDNSOutput.current(), localName);
      int l = offset(j);
      paramDNSOutput.writeByteArray(this.name, l, 1 + this.name[l]);
      ++j;
    }
  }

  public void toWire(DNSOutput paramDNSOutput, Compression paramCompression, boolean paramBoolean)
  {
    if (paramBoolean)
      toWireCanonical(paramDNSOutput);
    while (true)
    {
      return;
      toWire(paramDNSOutput, paramCompression);
    }
  }

  public byte[] toWire()
  {
    DNSOutput localDNSOutput = new DNSOutput();
    toWire(localDNSOutput, null);
    return localDNSOutput.toByteArray();
  }

  public void toWireCanonical(DNSOutput paramDNSOutput)
  {
    paramDNSOutput.writeByteArray(toWireCanonical());
  }

  public byte[] toWireCanonical()
  {
    byte[] arrayOfByte1;
    int j;
    Object localObject;
    int i = labels();
    if (i == 0)
      localObject = new byte[0];
    while (true)
    {
      return localObject;
      arrayOfByte1 = new byte[this.name.length - offset(0)];
      j = 0;
      int k = offset(0);
      l = 0;
      i1 = k;
      if (j < i)
        break;
      localObject = arrayOfByte1;
    }
    int i2 = this.name[i1];
    if (i2 > 63)
      throw new IllegalStateException("invalid label");
    int i3 = l + 1;
    byte[] arrayOfByte2 = this.name;
    int i4 = i1 + 1;
    arrayOfByte1[l] = arrayOfByte2[i1];
    int i5 = 0;
    int l = i3;
    int i1 = i4;
    while (true)
    {
      while (i5 >= i2)
        ++j;
      int i6 = l + 1;
      byte[] arrayOfByte3 = lowercase;
      byte[] arrayOfByte4 = this.name;
      int i7 = i1 + 1;
      arrayOfByte1[l] = arrayOfByte3[(0xFF & arrayOfByte4[i1])];
      i5 += 1;
      l = i6;
      i1 = i7;
    }
  }

  public Name wild(int paramInt)
  {
    if (paramInt < 1)
      throw new IllegalArgumentException("must replace 1 or more labels");
    try
    {
      Name localName = new Name();
      copy(wild, localName);
      localName.append(this.name, offset(paramInt), getlabels() - paramInt);
      return localName;
    }
    catch (NameTooLongException localNameTooLongException)
    {
      throw new IllegalStateException("Name.wild: concatenate failed");
    }
  }
}